package com.kaixinff.kaixin001.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.json.JSONException;
import org.json.JSONObject;

import com.kaixinff.kaixin001.common.Encrypt;
import com.kaixinff.net.HttpClient;
import com.kaixinff.net.HttpResponse;
import com.kaixinff.net.NameValuePair;
import com.kaixinff.net.ProxyManager;

public class KXClient extends HttpClient {

	private String email;
	private boolean isLogin;
	private boolean isNew;
	private Proxy proxy;
	private boolean useProxy;
	
	private static Map<String, KXClient> instances = new HashMap<String, KXClient>();
	
	public static KXClient getInstance(String email) throws IOException{
		return getInstance(email, false);
	}
	
	public static KXClient getInstance(String email, boolean isNew) throws IOException{
		setGlobalProxy(KXUtil.GLOBAL_PROXY);
		String key = email + "@" + isNew;
		KXClient instance = instances.get(key);
		if (instance == null) {
			instance = new KXClient(email, isNew);
			if (!isNew) {
				instance.init();
			}
			instances.put(key, instance);
		}
		if (!isNew) {
			String cookie = instance.getCookie("_user");
			if (!cookie.startsWith("_user=") || cookie.startsWith("_user=deleted;")) {
				instance.login();
			}
		}
		return instance;
	}
	
	private KXClient() {
		super(true);
	}
	
	private KXClient(String email, boolean isNew) throws IOException {
		super(true);
		this.email = email;
		this.isNew = isNew;
	}
	
	public String getEmail() {
		return email;
	}
	
	public boolean isUseProxy() {
		return useProxy;
	}

	public void setUseProxy(boolean useProxy) {
		this.useProxy = useProxy;
	}
	
	public void changeProxy() throws IOException {
		proxy = ProxyManager.getProxy(true);
		super.setProxy(proxy);
		System.out.println("Change proxy");
	}
	
	public HttpResponse doPost(String url, String referer, NameValuePair[] params, String charset) throws IOException {
		HttpResponse resp = null;
		IOException ex = null;
		if (useProxy) {
			if (proxy == null) {
				proxy = ProxyManager.getProxy();
			}
			super.setProxy(proxy);
		} else {
			super.setProxy(null);
		}
		for (int i = 0; i < 3; i++) {
			try {
				resp = super.doPost(url, referer, params, charset);
			} catch (IOException e) {
				e.printStackTrace();
				ex = e;
				if (proxy != null) {
					Proxy p2 = ProxyManager.getProxy();
					while (proxy.equals(p2)) {
						p2 = ProxyManager.getProxy();
					}
					proxy = p2;
					super.setProxy(proxy);
				} else {
					break;
				}
			}
			if (resp != null) {
				if (!relogin(resp)) {
					return resp;
				}
			}
		}
		throw ex;
	}
	
	public HttpResponse doGet(String url, String referer, String charset) throws IOException {
		HttpResponse resp = null;
		IOException ex = null;
		if (useProxy) {
			if (proxy == null) {
				proxy = ProxyManager.getProxy();
			}
			super.setProxy(proxy);
		} else {
			super.setProxy(null);
		}
		for (int i = 0; i < 3; i++) {
			try {
				resp = super.doGet(url, referer, charset);
			} catch (IOException e) {
				e.printStackTrace();
				ex = e;
				if (proxy != null) {
					Proxy p2 = ProxyManager.getProxy();
					while (proxy.equals(p2)) {
						p2 = ProxyManager.getProxy();
					}
					proxy = p2;
					super.setProxy(proxy);
				} else {
					break;
				}
			}
			if (resp != null) {
				if (!relogin(resp)) {
					return resp;
				}
			}
		}
		throw ex;
	}
	
	public boolean relogin(HttpResponse resp) throws IOException {
		if ("<script language=javascript>new parent.dialog().reset();</script>".equals(resp.getContent())) {
			isLogin = false;
			login();
			return true;
		}
		return false;
	}
	
	public boolean isLogined() {
		return isLogin;
	}
	
	private void init() throws IOException{
		URI uri = KXUtil.getFileURI("cookies/kaixin001.com/" + email + ".txt");
		File f = new File(uri);
		if (f.exists()) {
			List<String> cookies = new ArrayList<String>();
			LineNumberReader in = null;
			try {
				in = new LineNumberReader(new InputStreamReader(new FileInputStream(f), "UTF-8"));
				String str = null;
				while ((str = in.readLine()) != null) {
					if (str.startsWith("_user=") && !str.startsWith("_user=deleted;")) {
						isLogin = true;
					}
					cookies.add(str);
				}
			} finally {
				if (in != null) {
					in.close();
				}
			}
			super.setCookies(cookies);
		} 
		if (!isLogin){
			login();
		}
	}
	
	public String getEncypt() throws IOException{
		String html = doGet(KXUtil.LOGIN_URL, null).getContent();
		String encypt = null;
		Pattern p = Pattern.compile("var loginMgr = new EnLogin[(]'(.+?)'");
		Matcher m = p.matcher(html);
		if (m.find()) {
			encypt = m.group(1);
		}
		return encypt;
	}
	
	public void login() throws IOException {
		login(null, null, getEncypt());
	}
	
	public void login(String rcode, String code, String encypt) throws IOException {
		List<NameValuePair> params = new ArrayList<NameValuePair>();
		params.add(new NameValuePair("ver", "1"));
		params.add(new NameValuePair("email", email));
		params.add(new NameValuePair("rpasswd", Encrypt.enp(KXUtil.getPassword(), encypt)));
		params.add(new NameValuePair("encypt", encypt));
		params.add(new NameValuePair("url", "/home/"));
		params.add(new NameValuePair("remember", "1"));
		params.add(new NameValuePair("invisible_mode", "0"));
		if (rcode != null && code != null) {
			params.add(new NameValuePair("rcode", rcode));
			params.add(new NameValuePair("code", code));
		}
		String html = doPost(KXUtil.LOGIN_URL + "/login/login_api.php",
				KXUtil.LOGIN_URL + "/", params.toArray(new NameValuePair[]{})).getContent();
		try {
			JSONObject jobj = new JSONObject(html);
			if (jobj.has("loc")) {
				String loc = jobj.getString("loc");
				String url = KXUtil.LOGIN_URL + loc;
				if ("/reg/wizard.php".equals(loc)) {
					wizard(url);
				} else {
					int index = loc.indexOf("?uid=");
					if (index > -1) {
						String uid = loc.substring(loc.indexOf("?uid=") + 5);
						Properties p = KXUtil.getUid2Email();
						if (!p.containsKey(uid)) {
							p.put(uid, email);
							KXUtil.saveUid2Email();
						}
						html = doGet(url, null).getContent();
						isLogin = true;
						System.out.println("Login: " + email);
					}
				}
			} 
			if (!isLogin) {
				System.err.println(html);
			}
		} catch (JSONException e) {
			throw new IOException(e);
		}
//		if (isLogin) {
//			Collection<String> cookies = super.getCookies();
//			String path = getCookieFileName();
//			File f = new File(path);
//			FileOutputStream out = null;
//			try {
//				out = new FileOutputStream(f);
//				for (String cookie : cookies) {
//					out.write(cookie.getBytes("UTF-8"));
//					out.write('\r');
//					out.write('\n');
//				}
//			} finally {
//				if (out != null) {
//					out.close();
//				}
//			}
//		}
	}
	
	protected void setCookie(HttpURLConnection conn) throws IOException {
		super.setCookie(conn);
		if (!isNew) {
			Collection<String> cookies = super.getCookies();
			URI uri = KXUtil.getFileURI("cookies/kaixin001.com/" + email + ".txt");
			File f = new File(uri);
			if (!f.exists()) {
				File p = f.getParentFile();
				p.mkdirs();
				f.createNewFile();
			}
			FileOutputStream out = null;
			try {
				out = new FileOutputStream(f);
				for (String cookie : cookies) {
					out.write(cookie.getBytes("UTF-8"));
					out.write('\r');
					out.write('\n');
				}
			} finally {
				if (out != null) {
					out.close();
				}
			}
		}
	}

	private void wizard(String url) throws IOException {
		
		String referer = null;
		HttpResponse resp = doGet(url, referer);
		
		referer = KXUtil.HOST_URL + "/reg/wizard_email.php";
		if (resp.getURL().toString().equals(referer)) {
			url = KXUtil.HOST_URL + "/reg/wizard.php?action=skip&step=0";
			resp = doGet(url, referer);
		}
		
		referer = KXUtil.HOST_URL + "/reg/wizard_msn.php";
		if (resp.getURL().toString().equals(referer)) {
			url = KXUtil.HOST_URL + "/reg/wizard.php?action=skip&step=1";
			resp = doGet(url, referer);
		}
		
		referer = KXUtil.HOST_URL + "/reg/wizard_info.php";
		if (resp.getURL().toString().equals(referer)) {
			url = KXUtil.HOST_URL + "/reg/wizard_info_submit.php";
			resp = doPost(url, referer, new NameValuePair[]{
					new NameValuePair("city", "上海"),
					new NameValuePair("hometown", "上海"),
					new NameValuePair("status", "0")
			});
			
			url = KXUtil.HOST_URL + "/reg/wizard_mayknown.php";
			resp = doGet(url, referer);
		}
		
		referer = KXUtil.HOST_URL + "/reg/wizard_mayknown.php";
		if (resp.getURL().toString().equals(referer)) {
			url = KXUtil.HOST_URL + "/reg/wizard.php?action=skip&step=3";
			resp = doGet(url, referer);
		}
		
		referer = KXUtil.HOST_URL + "/reg/wizard_logo.php";
		if (resp.getURL().toString().equals(referer)) {
			url = KXUtil.HOST_URL + "/reg/wizard.php?action=skip&step=4";
			resp = doGet(url, referer);
		}
		
		Pattern p = Pattern.compile("[?]uid=(\\d+?)$");
		Matcher m = p.matcher(resp.getURL().toString());
		if (m.find()) {
			String uid = m.group(1);
			Properties uid2Email = KXUtil.getUid2Email();
			if (!uid2Email.contains(uid)) {
				uid2Email.put(uid, email);
				KXUtil.saveUid2Email();
			}
			isLogin = true;
			System.out.println("Login: " + email);
		}
	}
}
